package com.keepers.repair.utils

import com.google.gson.Gson
import com.keepers.repair.model.*
import com.keepers.repair.net.AsyncOkHttpClient
import com.keepers.repair.webservice.ChatService
import com.keepers.repair.webservice.ClientService
import com.keepers.repair.webservice.GroupService
import com.keepers.repair.webservice.UserService
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.functions.BiFunction
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.Result
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.simplexml.SimpleXmlConverterFactory

object Api {

    private val builder = Retrofit.Builder()
        .client(AsyncOkHttpClient.getOkHttpClient())
        .addConverterFactory(SimpleXmlConverterFactory.create())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    private var gson = Gson()
    private var retrofit: Retrofit? = null

    var clientService: ClientService? = null
    var userService: UserService? = null
    var groupService: GroupService? = null
    var chatService: ChatService? = null

    /**
     * 修改baseUrl
     *
     * @param url 要修改的 URL
     */
    fun setBaseUrl(url: String) {
        this.retrofit = builder.baseUrl(url).build()
        clientService = retrofit?.create(ClientService::class.java)
        userService = retrofit?.create(UserService::class.java)
        groupService = retrofit?.create(GroupService::class.java)
        chatService = retrofit?.create(ChatService::class.java)
    }

    /**
     * 服务器测试
     *
     * @param successCallback 测试成功的回调
     * @param failedCallback 测试失败的回调
     */
    fun hello(successCallback: (String) -> Unit, failedCallback: (Throwable) -> Unit) {
        clientService?.hello()?.call({ result ->
            result.response()?.body()?.content?.apply(successCallback)
        }, { err ->
            failedCallback(err)
        })
    }

    /**
     * 登录
     *
     * @param username 用户名
     * @param password 用户密码
     * @param callback 回调
     */
    fun login(username: String, password: String, callback: (UserModel?) -> Unit): Disposable? {
        val observable = userService?.login(username, password)
        return observable?.subscribeOn(Schedulers.io())
            ?.observeOn(AndroidSchedulers.mainThread())
            ?.subscribe({ result ->
                if (result.isError) {
                    throw result.error()!!
                }
                val content = result.response()?.body()?.content
                val loginJsonModel = gson.fromJson<LoginModel>(content, LoginModel::class.java)
                callback(loginJsonModel.Users[0])
            }, { err ->
                err.printStackTrace()
                callback(null)
            })
    }

    /**
     * 退出登录
     *
     * @param username 用户名
     * @param callback 回调
     */
    fun logout(username: String, callback: (Boolean) -> Unit) {
        val observable = userService?.logout(username)
        observable?.subscribeOn(Schedulers.io())
            ?.observeOn(AndroidSchedulers.mainThread())
            ?.subscribe({ result ->
                if (result.isError) {
                    throw result.error()!!
                }
                val content = result.response()?.body()?.content
                val value = gson.fromJson<Boolean>(content, Boolean::class.java)
                callback(value)
            }, { err ->
                err.printStackTrace()
                callback(false)
            })
    }

    /**
     * 获取任务列表
     *
     * @param groupGid
     * @param userGid
     * @param callback
     */
    fun getTasks(groupGid: String, userGid: String, callback: (List<TaskModel>) -> Unit) {
        userService?.getTaskList(groupGid, userGid)?.call({ result ->
            val content = result.response()?.body()?.content
            val value = gson.fromJson<TasksModel>(content, TasksModel::class.java)
            callback(value.tasks)
        }, { _ ->
            callback(listOf())
        })
    }

    /**
     * 获取通知列表
     *
     * @param groupGid
     * @param userGid
     * @param callback
     */
    fun getNotification(groupGid: String, userGid: String, callback: (List<NotificationModel>) -> Unit) {
        userService?.getNoticeList(groupGid, userGid)?.call({ result ->
            val content = result.response()?.body()?.content
            val value = gson.fromJson<NotificationsModel>(content, NotificationsModel::class.java)
            callback(value.Notice)
        }, { _ ->
            callback(listOf())
        })
    }

    /**
     * 获取组内用户列表
     * @param groupGid
     * @param callback
     */
    fun getUserList(groupGid: String, callback: (List<UserModel>) -> Unit) {
        val userListObservable = groupService?.getUserList(groupGid)
        val onlineListObservable = groupService?.getOnlineUserList(groupGid)
        val zipper = BiFunction<Result<XmlRootModel>, Result<XmlRootModel>, List<UserModel>> { t1, t2 ->
            val userContent = t1.response()?.body()?.content
            val onlineContent = t2.response()?.body()?.content
            val userList = gson.fromJson<GroupsModel>(userContent, GroupsModel::class.java).users
            val onlineList = gson.fromJson<OnlineModel>(onlineContent, OnlineModel::class.java).users

            for (user in userList) {
                user.Online = onlineList.contains(user)
            }
            userList
        }

        Observable.zip(userListObservable, onlineListObservable, zipper)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io())
            .subscribe({ users ->
                callback(users)
            }, { err ->
                err.printStackTrace()
            })
    }

    /**
     * 生成维修单
     *
     * @param userId     操作用户 ID
     * @param groupGid   操作用户所属组织 ID
     * @param gpsId      巡检数据 ID
     * @param to         要分配德维修人员 ID
     * @param info       检修信息
     * @param callback   回调
     */
    fun makeRepair(
        userId: String,
        groupGid: String,
        gpsId: String,
        info: String,
        to: String,
        callback: (Boolean) -> Unit
    ) {
        clientService?.makeRepair(userId, groupGid, gpsId, to, info)?.call({ result ->
            val content = result.response()?.body()?.content
            val value = gson.fromJson<Boolean>(content, Boolean::class.java)
            callback(value)
        }, { _ ->
            callback(false)
        })
    }

    /**
     * 获取维修单列表
     *
     * @param userId
     * @param groupGid
     * @param callback 回调
     */
    fun getRepairList(
        userId: String,
        groupGid: String,
        callback: (List<RepairModel>) -> Unit
    ) {
        userService?.getRepairList(userId, groupGid)?.call({ result ->
            val content = result.response()?.body()?.content
            val value = gson.fromJson<RepairListModel>(content, RepairListModel::class.java)
            callback(value.RepairTableList)
        }, { _ ->
            callback(listOf())
        })
    }

    /**
     * 获取聊天记录
     *
     * @param groupGid   用户组 ID
     * @param userId     用户 ID
     * @param count      获取记录的数量
     * @param chattingID 获取纪录的起始 ID
     * @param state      获取纪录的方向
     * @param callback   回调
     */
    fun getChatHistory(
        userId: String,
        groupGid: String,
        count: Int = 20,
        chattingID: Int = Int.MAX_VALUE,
        state: Int = ChatState.EARLIER.value,
        callback: (List<ChatHistoryItemModel>) -> Unit
    ) {
        chatService?.getChatRecords(groupGid, userId, count, chattingID, state)?.call({ result ->
            val content = result.response()?.body()?.content
            val list = gson.fromJson<ChatHistoryModel>(content, ChatHistoryModel::class.java)
            callback(list.ChattingRecords)
        }, { _ ->
            callback(listOf())
        })
    }

    /**
     * 上传聊天语音
     *
     * @param fileInfo  语音文件流信息
     * @param fileName  文件保存名
     * @param userId    用户 ID
     * @param groupGid  用户组 ID
     * @param length    语音的时长
     */
    fun uploadChatVoice(
        userId: String,
        groupGid: String,
        fileInfo: String,
        fileName: String,
        length: Int,
        callback: (String?) -> Unit
    ) {
        chatService?.saveChatVoice(
            FileInfor = fileInfo,
            SaveName = fileName,
            UserID = userId,
            GroupGid = groupGid,
            WhenLong = length
        )?.call({ result ->
            val content = result.response()?.body()?.content
            callback(content)
        }, { _ ->
            callback(null)
        })
    }

    /**
     * 改变语音消息的状态
     *
     * @param id       消息的 ID
     * @param callback 回调
     */
    fun changeVoiceState(id: String, callback: (Boolean) -> Unit) {
        chatService?.voiceChangeState(id)?.call({ result ->
            val content = result.response()?.body()?.content
            val value = gson.fromJson<Boolean>(content, Boolean::class.java)
            callback(value)
        }, {
            callback(false)
        })
    }

    /**
     * 下载语音文件
     *
     * @param name     文件名
     * @param callback 回调
     */
    fun downloadChatVoice(name: String, callback: (ResponseBody?) -> Unit) {
        val url = Config.voiceUrl + name
        chatService?.downloadChatVoice(url)
            ?.subscribeOn(Schedulers.io())
            ?.observeOn(AndroidSchedulers.mainThread())
            ?.subscribe({ result ->
                val body = result.response()?.body()
                callback(body)
            }, { _ ->
                callback(null)
            })
    }
}
